<?php

/**
 * @param  int           $code
 * @param  string|array  $msg
 * @param  array         $data
 *
 * @return array
 */
function msg ($code, $msg = null, $data = []) {
	$arr = ['code' => $code];
	if (null !== $msg) {
		if (is_array($msg) || is_object($msg))
			$arr['data'] = $msg; else $arr['msg'] = $msg;
	}
	if (!empty($data) && is_array($data))
		$arr = array_merge($arr, $data);

	return $arr;
}

/**
 * @param  int           $code
 * @param  string|array  $msg
 * @param  array         $data
 *
 * @return string
 */
function jsonMsg ($code, $msg = null, $data = []) {
	return arr2json(msg($code, $msg, $data));
}

/**
 * @param  array  $arr
 * @param  bool   $pre
 *
 * @return string
 */
function arr2json ($arr = [], $pre = false) {
	$url_encode = function ($str) use (&$url_encode) {
		if (!is_array($str))
			return rawurlencode($str);

		foreach ($str as $key => $value)
			$str[rawurlencode($key)] = $url_encode($value);

		return $str;
	};

	return str_replace('\\/', '/', version_compare(phpversion(), '5.4', '<')
		? rawurldecode(json_encode(url_encode($arr))) : json_encode($arr,
			$pre ? JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES : JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
}

/**
 * 数组转http表单
 *
 * @param  array   $params     请求参数数组
 * @param  string  $splice     参数键值对连接符
 * @param  string  $separator  相邻参数之间连接符
 *
 * @return false|string
 */
function arr2params ($params, $splice = '=', $separator = '&') {
	if (!is_array($params)) return false;

	$array = [];
	foreach ($params as $k => $v)
		$array[] = $k . $splice . $v;

	return implode($separator, $array);
}

/**
 * [array2tree 一维数组转父子结构多维数组]
 *
 * @param  array  $list    [一维数组数据]
 * @param  array  $option  [默认父子字段名称、顶级id等选项]
 *
 * @return array          [父子结构多维数组]
 */
function array2tree ($list, $option = []) {
	$c = [
		'id'    => 'id',
		'pId'   => 'pId',
		'child' => 'child',
		'root'  => null
	];
	if (is_array($option))
		$c = array_merge($c, $option);

	$tree = [];
	if (is_array($list)) {
		$refer = [];
		foreach ($list as $key => $data)
			$refer[$data[$c['id']]] =& $list[$key];

		foreach ($refer as $key => $data) {
			$parentId = $data[$c['pId']];

			if ($c['root'] === $parentId) {
				$tree[$data[$c['id']]] =& $refer[$key];
			} else if (isset($refer[$parentId])) {
				$parent                               =& $refer[$parentId];
				$parent[$c['child']][$data[$c['id']]] =& $refer[$key];
				$parent[$c['child']]                  = array_values($parent[$c['child']]);
			}
		}
	}

	return array_values($tree);
}

/**
 * 二维数组根据某个字段排序
 *
 * @param  array   $arr   要排序的数组
 * @param  string  $key   要排序的键字段
 * @param  string  $sort  排序类型  SORT_ASC     SORT_DESC
 *
 * @return array 排序后的数组
 */
function arraySort ($arr, $key, $sort = SORT_ASC) {
	$keysValue = arr_column($arr, $key);
	array_multisort($keysValue, $sort, $arr);

	return $arr;
}

// array_column函数 低版php兼容及bug修复
function arr_column ($array, $column_key, $index_key = null) {
	if (version_compare(phpversion(), '7.0', '<')) {
		$arr = [];
		foreach ($array as $v) {
			$value = is_object($v) ? @$v->$column_key : @$v[$column_key];
			if ($index_key === null) $arr[] = $value;
			else $arr[is_object($v) ? @$v->$index_key : @$v[$index_key]] = $value;
		}

		return $arr;
	}

	return array_column($array, $column_key, $index_key);
}

/**
 * 同java  System.arraycopy
 *
 * @param  array  $src      原数组
 * @param  int    $srcPos   原数组的起始索引
 * @param  array  $dest     目标数组
 * @param  int    $destPos  目标数组起始索引
 * @param  int    $length   要复制的数组的长度
 *
 * @return void
 */
function arraycopy ($src, $srcPos, &$dest, $destPos, $length) {
	array_splice($dest, $destPos, $length, array_slice($src, $srcPos, $length));
}

/**
 * [autoSize 大小单位自动转换]
 *
 * @param  int     $size       字节大小
 * @param  string  $separator  连接符
 *
 * @return int|string
 */
function autoSize ($size, $separator = ' ') {
	$units  = str_split(' KMGTP');
	$factor = floor((strlen($size) - 1) / 3);

	return ($size >= 1024) ? sprintf("%.2f", $size / pow(1024, $factor)) . $separator . @$units[$factor] : $size;
}

/**
 * 获取13位时间戳
 *
 * @param  int  $len  长度 10-18，常用10和13
 *
 * @return int
 */
function longTime ($len = 13) {
	return intval(microtime(true) * pow(10, $len - 10));
}

/**
 * 随机字符串
 *
 * @param  int  $len  长度
 *
 * @return string
 */
function randKey ($len) {
	$arr = str_shuffle("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
	$key = '';
	for ($i = 0; $i < 16; $i++) $key .= $arr[$i];

	return $key;
}

function uuid () {
	$charid = md5(uniqid(mt_rand(), true));
	$hyphen = chr(45);

	return substr($charid, 0, 8) . $hyphen
		. substr($charid, 8, 4) . $hyphen
		. substr($charid, 12, 4) . $hyphen
		. substr($charid, 16, 4) . $hyphen
		. substr($charid, 20, 12);
}

/**
 * 获取客户端真实ip地址
 *
 * @param  boolean  $proxy  是否获取代理ip地址
 *
 * @return string
 */
function getip ($proxy = false) {
	if (!$proxy) return $_SERVER['REMOTE_ADDR'];

	if (isset($_SERVER['HTTP_CLIENT_IP']))
		$ip = $_SERVER['HTTP_CLIENT_IP'];
	else if (isset($_SERVER['HTTP_FORWARDED']))
		$ip = $_SERVER['HTTP_FORWARDED'];
	else if (isset($_SERVER['HTTP_X_FORWARDED_FOR']))
		$ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
	else
		$ip = $_SERVER['REMOTE_ADDR'];

	return $ip;
}

// session 操作封装
function session (...$args) {
	$status = version_compare(phpversion(), '5.4.0', '>=') ? session_status() === PHP_SESSION_ACTIVE : session_id() !== '';
	if (!$status) session_start();

	$length = count($args);
	if ($length > 1)
		if ($args[1] === null || $args[1] === '')
			unset($_SESSION[$args[0]]);
		else
			$_SESSION[$args[0]] = $args[1];
	else if (is_array($args[0]))
		foreach ($args[0] as $k => $v) {
			if ($v === null || $v === '')
				unset($_SESSION[$k]);
			else
				$_SESSION[$k] = $v;
		}
	else
		return isset($_SESSION[$args[0]]) ? $_SESSION[$args[0]] : null;

	return true;
}

/**
 * cookie 操作封装
 *
 * @param  string  $name
 * @param  string  $value
 * @param  int     $expire
 *
 * @return string|true
 */
function cookie ($name, $value = false, $expire = null) {
	if ($value === false)
		return @$_COOKIE[$name];

	$dir = preg_replace('/\/+[^\/?]*(\?.*)?$/', '/', @$_SERVER['REQUEST_URI']);

	if (($value === null || $value === '') && isset($_COOKIE[$name]))
		setcookie($name, '', time() - 3600, $dir, $_SERVER['HTTP_HOST']);
	else
		setcookie($name, $value, is_numeric($expire) ? time() + $expire : null, $dir, $_SERVER['HTTP_HOST']);

	return true;
}

/**
 * 删除目录
 *
 * @param  string  $dir   [目录路径]
 * @param  bool    $self  [是否删除自身]
 */
function del_dir ($dir, $self = true) {
	array_map(function ($path) {
		$name = basename($path);
		if ('.' === $name || '..' === $name)
			return;
		if (is_dir($path)) {
			del_dir($path, false);
			@rmdir($path);
		} else if (!@unlink($path) && chmod($path, 0777))
			@unlink($path);
	}, glob($dir . DIRECTORY_SEPARATOR . '{.*,*}', GLOB_BRACE));
	if ($self && file_exists($dir))
		@rmdir($dir);
}

/**
 * 自动编码转换
 *
 * @param  string  $str
 * @param  string  $charset
 *
 * @return string
 */
function charset ($str, $charset = 'UTF-8') {
	$encode = mb_detect_encoding($str, ["ASCII", "GB2312", "GBK", 'UTF-8', 'BIG5']);
	if ($encode !== false && $encode !== strtoupper($charset))
		$str = mb_convert_encoding($str, $charset, $encode);

	return $str;
}

/**
 * url地址仅中文和符号参数编码
 *
 * @param  $url
 *
 * @return string
 */
function url_encode ($url) {
	$uri   = '';
	$chars = unpack('C*', $url);
	$len   = count($chars);
	for ($i = 1; $i <= $len; $i++)
		$uri .= $chars[$i] > 127 || $chars[$i] === 32 ? '%' . strtoupper(dechex($chars[$i])) : $url[$i - 1];

	return $uri;
}

/**
 * 获取当前url对应的目录url
 *
 * @param  boolean  $host    是否需要域名
 * @param  boolean  $scheme  是否需要协议头
 *
 * @return string
 */
function request_dir ($host = true, $scheme = true) {
	$ret = '';
	if ($scheme) $ret .= @$_SERVER['HTTPS'] === 1 || @$_SERVER['HTTPS'] === 'on' || @$_SERVER['SERVER_PORT'] === 443 ? 'https://' : 'http://';
	if ($host) $ret .= @$_SERVER['HTTP_HOST'];
	$ret .= preg_replace('/\/+[^\/?]*(\?.*)?$/', '', @$_SERVER['REQUEST_URI']) . '/';

	return $ret;
}

/*
 * 字符串 => 字节数组
 *
 * @param  int    $str   要复制的数组的长度
 *
 * @return array
 */
function getBytes ($str) {
	return array_values(unpack("c*", $str));
}

/**
 * 字节数组 => 字符串
 *
 * @param  array  $bytes
 *
 * @return false|string
 */
function bytes2Str ($bytes) {
	return pack("c*", ...$bytes);
}

/**
 * int转字节byte
 *
 * @param  int  $num
 *
 * @return false|int
 */
function int2byte ($num) {
	$arr = unpack('c*', pack('l', $num));

	return reset($arr);
}

/**
 * 处理int32系统位溢出溢出
 *
 * @param  int  $num
 *
 * @return false|int
 */
function intval32 ($num) {
	$arr = unpack("l", pack("l", $num));

	return reset($arr);
}

/**
 * 逻辑右移 (a >>> n)
 *
 * @param  int  $a
 * @param  int  $n
 *
 * @return int
 */
function uright ($a, $n) {
	if (0 === $n)
		return $a;

	if ($n < 0)
		return 0;

	return (2147483647 >> ($n - 1)) & ($a >> $n);
}

/**
 * 判断是否标准json字符串
 *
 * @param  string   $str          json字符串
 * @param  boolean  $associative  是否解析为数组
 *
 * @return false|mixed
 */
function is_json ($str, $associative = false) {
	return $str !== null && preg_match('/(^[{\[]|[}\[]$)/', $str) && (null !== $obj = json_decode($str, $associative)) && json_last_error() == JSON_ERROR_NONE ? $obj : false;
}

// post数据
function p ($key, $value = null) {
	return isset($_POST[$key]) && $_POST[$key] !== '' ? $_POST[$key] : $value;
}

// get数据
function g ($key, $value = null) {
	return isset($_GET[$key]) && $_GET[$key] !== '' ? $_GET[$key] : $value;
}

// request数据
function r ($key, $value = null) {
	return isset($_REQUEST[$key]) && $_REQUEST[$key] !== '' ? $_REQUEST[$key] : $value;
}